/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.lock.service.memory;



import io.iec.edp.caf.commons.exception.ExceptionLevel;
import io.iec.edp.caf.lock.service.api.api.DistributedLock;
import io.iec.edp.caf.lock.service.api.api.DistributedLockFactory;
import io.iec.edp.caf.lock.service.api.exception.DLErrorDefinition;
import io.iec.edp.caf.lock.service.api.exception.DistributedLockException;

import java.time.Duration;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class MemoryLockFactoryImpl implements DistributedLockFactory {
    private final Lock memLock = new ReentrantLock();

    private static ConcurrentHashMap<String, Lock> map = new ConcurrentHashMap();
    private static ConcurrentHashMap<String, Integer> refs = new ConcurrentHashMap();

    @Override
    public DistributedLock createLock(String resource, Duration expiryTime) {
        try {
            Lock lock = null;
            synchronized (resource) {
                if (!refs.containsKey(resource)) {
                    refs.put(resource, 1);
                }
                lock = map.computeIfAbsent(resource, k -> new ReentrantLock());
                refs.computeIfPresent(resource, (k, v) -> v + 1);
            }
            lock.tryLock(expiryTime.getSeconds()*1000,TimeUnit.SECONDS);
            return new MemoryLockImpl(resource, true, map, refs);
        } catch (Exception e) {
            throw new DistributedLockException("pfcomm", DLErrorDefinition.AddLock_IsAcquired_Error, null, e, ExceptionLevel.Error, false);
        }
    }

    @Override
    public DistributedLock CreateLock(String resource, Duration expiryTime) {
        return createLock(resource, expiryTime);
    }

    @Override
    public DistributedLock createLock(String resource, Duration expiryTime, Duration waitTime, Duration retryTime) {
        try {
            Lock lock = null;
            synchronized (resource) {
                if (!refs.containsKey(resource)) {
                    refs.put(resource, 1);
                }
                lock = map.computeIfAbsent(resource, k -> new ReentrantLock());
                refs.computeIfPresent(resource, (k, v) -> v + 1);
            }
            lock.tryLock(expiryTime.getSeconds()*1000,TimeUnit.SECONDS);
            return new MemoryLockImpl(resource, true, map, refs);
        } catch (Exception e) {
            throw new DistributedLockException("pfcomm", DLErrorDefinition.AddLock_IsAcquired_Error, null, e, ExceptionLevel.Error, false);
        }
    }



    @Override
    public DistributedLock createMultiLock(String resoucePrefix, List<String> dataIds, Duration expiryTime){
       return this.createLock(resoucePrefix,expiryTime);
    }
    /**
     *尝试获取锁，当超过waitTime时仍没有获取到锁时则直接返回
     */
    @Override
    public DistributedLock tryCreateLock(Duration waitTime,String resource, Duration expiryTime) throws InterruptedException{
        //todo:memoryLock对该方法的实现
        return null;
    }

    @Override
    public DistributedLock tryCreateLock(String resource){
        //todo:memoryLock对该方法的实现
        return  null;
    }
}
